import { camelize, hasOwn, isArray, isFunction, isObject, isString } from '@web-utils/core'
import { formatDate } from '@web-utils/integrations/dayjs'
import AsyncValidator from 'async-validator'
import { aesEncryptBiz, base64Encode } from '@/views/login/verifition/utils/ase'
import { request } from '@/http'
import { validatenull } from '@/util/validate'
import { Message } from 'element-ui'
import { transparentImage } from '@/const'

export * from './file'

/**
 * 判断两个时间大小
 */
export function checkStartEndDate(startDate, endDate) {
  const date = new Date(startDate)
  const date1 = new Date(endDate)
  return date.getTime() - date1.getTime() > 0
}

export function patch(target, patch, append = true) {
  if (isObject(patch)) {
    for (const patchKey in patch) {
      if (append) {
        target[patchKey] = patch[patchKey]
      } else {
        if (hasOwn(target, patchKey)) {
          target[patchKey] = patch[patchKey]
        }
      }
    }
  }
  return target
}

export const findParent = (vm, predicate) => {
  if (!vm || !predicate) {
    return null
  }

  let parent = vm

  while (parent && predicate(parent)) {
    parent = parent.$parent
  }

  return parent
}

export function setNull(target, props, append = false) {
  let properties
  if (isString(props)) {
    properties = props.split(',')
  } else if (isArray(props)) {
    properties = props
  } else {
    return target
  }
  if (isArray(properties)) {
    properties.forEach(prop => {
      if (append) {
        target[prop] = null
      } else {
        if (hasOwn(target, prop)) {
          target[prop] = null
        }
      }
    })
  }
  return target
}

export const getQuarter = date => {
  const moth = date.getMonth() + 1
  const year = date.getFullYear()
  if ([1, 2, 3].includes(moth)) {
    return {
      start: `${year}-1-1`,
      end: `${year}-3-31`
    }
  } else if ([4, 5, 6].includes(moth)) {
    return {
      start: `${year}-4-1`,
      end: `${year}-6-30`
    }
  } else if ([7, 8, 9].includes(moth)) {
    return {
      start: `${year}-7-1`,
      end: `${year}-9-30`
    }
  } else if ([10, 11, 12].includes(moth)) {
    return {
      start: `${year}-10-1`,
      end: `${year}-12-31`
    }
  } else {
    return {
      start: '',
      end: ''
    }
  }
}

export const getHalfYear = date => {
  const moth = date.getMonth() + 1
  const year = date.getFullYear()

  if ([1, 2, 3, 4, 5, 6].includes(moth)) {
    return {
      start: `${year}-1-1`,
      end: `${year}-6-30`
    }
  } else if ([7, 8, 9, 10, 11, 12].includes(moth)) {
    return {
      start: `${year}-7-1`,
      end: `${year}-12-31`
    }
  } else {
    return {
      start: '',
      end: ''
    }
  }
}

export const getPercent = percent => {
  return window.isNaN(percent) ? 0 : percent
}

const toObject = keys => {
  const temp = {}
  keys.forEach(key => {
    temp[key] = null
  })
  return temp
}

export const genEmptyRow = columns => {
  return toObject(columns.map(value => value.prop))
}

export const assignEmptyRow = (entity, prop, columns) => {
  entity[prop] = entity[prop]?.length ? entity[prop] : [genEmptyRow(columns)]
}

export const arrayToObject = (array, key) => {
  const tmp = {}
  if (array?.length) {
    array.forEach(value => {
      tmp[value[key]] = value
    })
  }
  return tmp
}

const elTableProperties = [
  'data',
  'height',
  'max-height',
  'stripe',
  'border',
  'size',
  'fit',
  'show-header',
  'highlight-current-row',
  'current-row-key',
  'row-class-name',
  'row-style',
  'cell-class-name',
  'cell-style',
  'header-row-class-name',
  'header-row-style',
  'header-cell-class-name',
  'header-cell-style',
  'row-key',
  'empty-text',
  'default-expand-all',
  'expand-row-keys',
  'default-sort',
  'tooltip-effect',
  'show-summary',
  'sum-text',
  'summary-method',
  'span-method',
  'select-on-indeterminate ',
  'indent',
  'lazy',
  'load',
  'tree-props'
]

const elTableEvents = [
  'select',
  'select-all',
  'selection-change',
  'cell-mouse-enter',
  'cell-mouse-leave',
  'cell-click',
  'cell-dblclick',
  'row-click',
  'row-contextmenu',
  // 'row-dblclick',
  'header-click',
  'header-contextmenu',
  'sort-change',
  'filter-change',
  'current-change',
  'header-dragend',
  'expand-change'
]

const elTableColumnProperties = [
  'type',
  'index',
  'column-key',
  'label',
  'prop',
  'width',
  'min-width',
  'fixed',
  'render-header',
  'sortable',
  'sort-method',
  'sort-by',
  'sort-orders',
  'resizable',
  'formatter',
  'show-overflow-tooltip',
  'align',
  'header-align',
  'class-name',
  'label-class-name',
  'selectable',
  'reserve-selection',
  'filters',
  'filter-placement',
  'filter-multiple',
  'filter-method',
  'filtered-value'
]

const elTreeProperties = [
  'data',
  'empty-text',
  'node-key',
  'props',
  'render-after-expand',
  'load',
  'render-content',
  'highlight-current',
  'default-expand-all',
  'expand-on-click-node',
  'check-on-click-node',
  'auto-expand-parent',
  'default-expanded-keys',
  'show-checkbox',
  'check-strictly',
  'default-checked-keys',
  'current-node-key',
  'filter-node-method',
  'accordion',
  'indent',
  'icon-class',
  'lazy',
  'draggable',
  'allow-drag',
  'allow-drop'
]

const elTreeEvents = [
  'node-click',
  'node-contextmenu',
  'check-change',
  'check',
  'current-change',
  'node-expand',
  'node-collapse',
  'node-drag-start',
  'node-drag-enter',
  'node-drag-leave',
  'node-drag-over',
  'node-drag-end',
  'node-drop'
]

/**
 * 过滤对象中属性
 * @param obj 目标对象
 * @param allowProperties 允许出现的属性
 * @param allow 是否允许 allowProperties 中的属性出现，默认只留下在 allowProperties 中指定的属性，否的话会过滤掉 allowProperties 中指定的属性
 * @return {{}|*}
 */
export const filterProperties = (obj, allowProperties, allow = true) => {
  if (isObject(obj)) {
    let arr = allowProperties
    if (isString(allowProperties)) {
      arr = arr.split(',')
    }
    const temp = {}
    if (allow) {
      arr.forEach(key => {
        if (hasOwn(obj, key)) {
          temp[key] = obj[key]
        }
      })
    } else {
      for (const objKey in obj) {
        if (!arr.includes(objKey)) {
          temp[objKey] = obj[objKey]
        }
      }
    }
    return temp
  }
  return obj
}

export const normalizeProps = attrs => {
  const props = {}
  for (const attrsKey in attrs) {
    props[camelize(attrsKey)] = attrs[attrsKey]
  }
  return props
}

export const filterTableProperties = obj => {
  return filterProperties(obj, elTableProperties)
}

export const filterTableColumnProperties = obj => {
  return filterProperties(obj, elTableColumnProperties)
}

export const filterTableEvents = obj => {
  return filterProperties(obj, elTableEvents)
}

export const filterTreeProperties = obj => {
  return filterProperties(obj, elTreeProperties)
}

export const filterTreeEvents = obj => {
  return filterProperties(obj, elTreeEvents)
}

export const pathArgReplacer = (path = '', row = {}) => {
  const rw = row || {}
  const p = path || ''
  return p.replace(/{(.*?)}/g, (_, key) => {
    if (key.indexOf(':')) {
      const [k, defaultVal] = key.split(':')
      return rw[k] ? rw[k] : defaultVal
    } else {
      return rw[key] || ''
    }
  })
}

export const fillPath = (path, args) => {
  if (isFunction(path)) {
    return pathArgReplacer(path(args), args)
  } else if (isString(path)) {
    return pathArgReplacer(path, args)
  } else {
    return null
  }
}

/**
 * 获取制定年到当前年的所有年份
 */
export function getYearOptions() {
  const appointYear = 2021
  const myDate = new Date()
  let thisYear = myDate.getFullYear()
  const Section = thisYear - appointYear
  const arrYear = []
  for (let i = 0; i <= Section; i++) {
    arrYear.push(thisYear--)
  }
  return arrYear
}

export function getStartDate() {
  const nowDate = new Date()
  const year = nowDate.getFullYear()
  const y = { start: formatDate(new Date(year, 0, 1), 'YYYY-MM-DD') }
  return y.start
}

export function loadTheme(theme) {
  const html = document.getElementsByTagName('html')[0]
  if (html.classList.length > 0) {
    html.classList.remove(html.classList[0])
  }
  html.classList.add(`theme-${theme.value}`)
}

export async function validateProp(prop, value, rules) {
  return new Promise((resolve, reject) => {
    const descriptor = {}
    if (rules && rules.length > 0) {
      rules.forEach(rule => {
        delete rule.trigger
      })
    }
    descriptor[prop] = rules

    const validator = new AsyncValidator(descriptor)
    const model = {}

    model[prop] = value

    validator.validate(model, { firstFields: true }, (errors, invalidFields) => {
      if (!errors) {
        return resolve(true)
      } else {
        return resolve(false)
      }
    })
  })
}

/**
 *加密处理
 */
export const encryption = ({ data, type, param, key }) => {
  const result = JSON.parse(JSON.stringify(data))
  if (type === 'Base64') {
    param.forEach(ele => {
      result[ele] = base64Encode(result[ele])
    })
  } else {
    param.forEach(ele => {
      result[ele] = aesEncryptBiz(result[ele], key)
    })
  }
  return result
}

// 表单序列化
export const serialize = data => {
  const list = []
  Object.keys(data).forEach(ele => {
    list.push(`${ele}=${data[ele]}`)
  })
  return list.join('&')
}
/**
 * 对象深拷贝
 */
export const deepClone = data => {
  let obj
  if (isArray(data)) {
    obj = []
  } else if (isObject(data)) {
    obj = {}
  } else {
    // 不再具有下一层次
    return data
  }
  if (isArray(data)) {
    for (let i = 0, len = data.length; i < len; i++) {
      obj.push(deepClone(data[i]))
    }
  } else if (isObject(data)) {
    for (const key in data) {
      obj[key] = deepClone(data[key])
    }
  }
  return obj
}
/**
 * 判断路由是否相等
 */
export const diff = (obj1, obj2) => {
  delete obj1.close
  const o1 = obj1 instanceof Object
  const o2 = obj2 instanceof Object
  if (!o1 || !o2) {
    /*  判断不是对象  */
    return obj1 === obj2
  }

  if (Object.keys(obj1).length !== Object.keys(obj2).length) {
    return false
    // Object.keys() 返回一个由对象的自身可枚举属性(key值)组成的数组,例如：数组返回下表：let arr = ["a", "b", "c"];console.log(Object.keys(arr))->0,1,2;
  }

  for (const attr in obj1) {
    const t1 = obj1[attr] instanceof Object
    const t2 = obj2[attr] instanceof Object
    if (t1 && t2) {
      return diff(obj1[attr], obj2[attr])
    } else if (obj1[attr] !== obj2[attr]) {
      return false
    }
  }
  return true
}
/**
 * 设置灰度模式
 */
export const toggleGrayMode = status => {
  if (status) {
    document.body.className = `${document.body.className} grayMode`
  } else {
    document.body.className = document.body.className.replace(' grayMode', '')
  }
}
/**
 * 设置主题
 */
export const setTheme = name => {
  document.body.className = name
}

/**
 * 浏览器判断是否全屏
 */
export const fullscreenToggel = () => {
  if (fullscreenEnable()) {
    exitFullScreen()
  } else {
    reqFullScreen()
  }
}
/**
 * esc监听全屏
 */
export const listenfullscreen = callback => {
  function listen() {
    callback()
  }

  document.addEventListener('fullscreenchange', function () {
    listen()
  })
  document.addEventListener('mozfullscreenchange', function () {
    listen()
  })
  document.addEventListener('webkitfullscreenchange', function () {
    listen()
  })
  document.addEventListener('msfullscreenchange', function () {
    listen()
  })
}

/**
 * 浏览器判断是否全屏
 */
export const fullscreenEnable = () => {
  return document.isFullScreen || document.mozIsFullScreen || document.webkitIsFullScreen
}

/**
 * 浏览器全屏
 */
export const reqFullScreen = () => {
  if (document.documentElement.requestFullScreen) {
    document.documentElement.requestFullScreen()
  } else if (document.documentElement.webkitRequestFullScreen) {
    document.documentElement.webkitRequestFullScreen()
  } else if (document.documentElement.mozRequestFullScreen) {
    document.documentElement.mozRequestFullScreen()
  }
}
/**
 * 浏览器退出全屏
 */
export const exitFullScreen = () => {
  if (document.documentElement.requestFullScreen) {
    document.exitFullScreen()
  } else if (document.documentElement.webkitRequestFullScreen) {
    document.webkitCancelFullScreen()
  } else if (document.documentElement.mozRequestFullScreen) {
    document.mozCancelFullScreen()
  }
}
/**
 * 递归寻找子类的父类
 */

/**
 * 动态插入css
 */

export const loadStyle = url => {
  const link = document.createElement('link')
  link.type = 'text/css'
  link.rel = 'stylesheet'
  link.href = url
  const head = document.getElementsByTagName('head')[0]
  head.appendChild(link)
}
/**
 * 判断路由是否相等
 */
export const isObjectValueEqual = (a, b) => {
  let result = true
  Object.keys(a).forEach(ele => {
    const type = typeof a[ele]
    if (type === 'string' && a[ele] !== b[ele]) {
      result = false
    } else if (type === 'object' && JSON.stringify(a[ele]) !== JSON.stringify(b[ele])) {
      result = false
    }
  })
  return result
}
/**
 * 根据字典的value显示label
 */
export const findByvalue = (dic, value) => {
  let result = ''
  if (validatenull(dic)) return value
  if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
    let index = 0
    index = findArray(dic, value)
    if (index !== -1) {
      result = dic[index].label
    } else {
      result = value
    }
  } else if (value instanceof Array) {
    result = []
    let index = 0
    value.forEach(ele => {
      index = findArray(dic, ele)
      if (index !== -1) {
        result.push(dic[index].label)
      } else {
        result.push(value)
      }
    })
    result = result.toString()
  }
  return result
}
/**
 * 根据字典的value查找对应的index
 */
export const findArray = (dic, value) => {
  for (let i = 0; i < dic.length; i++) {
    if (dic[i].value === value) {
      return i
    }
  }
  return -1
}
/**
 * 生成随机len位数字
 */
export const randomLenNum = (len, date) => {
  let random
  random = Math.ceil(Math.random() * 100000000000000)
    .toString()
    .substr(0, len || 4)
  if (date) random = random + Date.now()
  return random
}
/**
 * 打开小窗口
 */
export const openWindow = (url, title, w, h) => {
  // Fixes dual-screen position                            Most browsers       Firefox
  const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left
  const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top

  const width = window.innerWidth
    ? window.innerWidth
    : document.documentElement.clientWidth
    ? document.documentElement.clientWidth
    : screen.width
  const height = window.innerHeight
    ? window.innerHeight
    : document.documentElement.clientHeight
    ? document.documentElement.clientHeight
    : screen.height

  const left = width / 2 - w / 2 + dualScreenLeft
  const top = height / 2 - h / 2 + dualScreenTop
  const newWindow = window.open(
    url,
    title,
    `toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=${w}, height=${h}, top=${top}, left=${left}`
  )

  // Puts focus on the newWindow
  if (window.focus) {
    newWindow.focus()
  }
}

export const getDataURL = async url => {
  const res = await request({ url, method: 'get', responseType: 'blob' })
  const blob = res.data
  if (blob.size === 0) {
    return null
  }
  const dataURL = URL.createObjectURL(blob)
  window.setTimeout(() => window.URL.revokeObjectURL(blob), 0)
  return dataURL
}

export const assignDataURLToImage = async (url, ref) => {
  ref.src = transparentImage
  ref.src = await getDataURL(url)
}

/**
 *
 * @param url 目标下载接口
 * @param query 查询参数
 * @param fileName 文件名称
 * @param method
 * @param data
 * @return {Promise<void>}
 */
export const downBlobFile = async (url, query, fileName, method = 'get', data = {}) => {
  const response = await request({ url, method, responseType: 'blob', params: query, data })
  // 处理返回的文件流
  const blob = response.data
  if (blob && blob.size === 0) {
    Message.error('内容为空，无法下载')
    return
  }
  const link = document.createElement('a')
  link.href = window.URL.createObjectURL(blob)
  link.download = fileName
  document.body.appendChild(link)
  link.click()
  window.setTimeout(() => {
    window.URL.revokeObjectURL(blob)
    document.body.removeChild(link)
  }, 0)
}

/**
 *
 * @param url
 * @param query
 * @param col
 * @param fileName
 * @return {Promise<void>}
 */
export const downBlobCustomeFile = (url, query, col, fileName) => {
  const headProperties = []
  for (let i = 0; i < col.length; i++) {
    if (!(col[i].hide === true)) {
      headProperties.push({
        prop: col[i].prop,
        label: col[i].label
      })
    }
  }
  return downBlobFile(url, query, fileName, 'post', headProperties)
}

export const zhLocale = {
  common: {
    condition: '条件',
    display: '显示',
    hide: '隐藏'
  },
  tip: {
    select: '请选择',
    input: '请输入'
  },
  upload: {
    upload: '点击上传',
    tip: '将文件拖到此处，或'
  },
  date: {
    start: '开始日期',
    end: '结束日期',
    t: '今日',
    y: '昨日',
    n: '近7天',
    a: '全部'
  },
  form: {
    printBtn: '打 印',
    mockBtn: '模 拟',
    submitBtn: '提 交',
    emptyBtn: '清 空'
  },
  crud: {
    filter: {
      addBtn: '新增条件',
      clearBtn: '清空数据',
      resetBtn: '清空条件',
      cancelBtn: '取 消',
      submitBtn: '确 定'
    },
    column: {
      name: '列名',
      hide: '隐藏',
      fixed: '冻结',
      filters: '过滤',
      sortable: '排序',
      index: '顺序',
      width: '宽度'
    },
    tipStartTitle: '当前表格已选择',
    tipEndTitle: '项',
    editTitle: '编 辑',
    copyTitle: '复 制',
    addTitle: '新 增',
    viewTitle: '查 看',
    filterTitle: '过滤条件',
    showTitle: '列显隐',
    menu: '操作',
    addBtn: '增 加',
    show: '显 示',
    hide: '隐 藏',
    open: '展 开',
    shrink: '收 缩',
    printBtn: '打 印',
    excelBtn: '导 出',
    updateBtn: '修 改',
    cancelBtn: '取 消',
    searchBtn: '搜 索',
    emptyBtn: '清 空',
    menuBtn: '功 能',
    saveBtn: '保 存',
    viewBtn: '查 看',
    editBtn: '编 辑',
    copyBtn: '复 制',
    delBtn: '删 除'
  }
}

export const getBrowser = () => {
  const explorer = window.navigator.userAgent.toLowerCase()
  if (explorer.indexOf('msie') >= 0) {
    const ver = explorer.match(/msie ([\d.]+)/)[1]
    return {
      name: 'IE',
      version: ver
    }
  } else if (explorer.indexOf('firefox') >= 0) {
    const ver = explorer.match(/firefox\/([\d.]+)/)[1]
    return {
      name: 'Firefox',
      version: ver
    }
  } else if (explorer.indexOf('chrome') >= 0) {
    const ver = explorer.match(/chrome\/([\d.]+)/)[1]
    return {
      name: 'Chrome',
      version: ver
    }
  } else if (explorer.indexOf('opera') >= 0) {
    const ver = explorer.match(/opera.([\d.]+)/)[1]
    return {
      name: 'Opera',
      version: ver
    }
  } else if (explorer.indexOf('Safari') >= 0) {
    const ver = explorer.match(/version\/([\d.]+)/)[1]
    return {
      name: 'Safari',
      version: ver
    }
  }

  return {
    name: 'Other',
    version: '1.0.0'
  }
}

export const generateUUID = () => {
  let d = new Date().getTime()
  const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
    const r = (d + Math.random() * 16) % 16 | 0
    d = Math.floor(d / 16)
    return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16)
  })
  return uuid.replace(/-/g, '')
}
